using System;
using System.Threading;

using Pegasus.Diagnostics;
using Pegasus.Log4Net;

namespace Pegasus.Threading
{
	/// <summary>
	/// Summary description for AppThread.
	/// </summary>
	internal class AppThread
	{
		// Local Instance Values
		private ILog m_log = LogManager.GetLogger( typeof( AppThread ) );
		private Thread m_thread;
		private AutoResetEvent m_goEvent = new AutoResetEvent( false );
		private bool m_running = false;
		private bool m_allDone = false;

		private WaitCallback m_callback = null;
		private object m_state = null;
				
		/// <summary>
		/// 
		/// </summary>
		public AppThread()
		{
			m_thread = new Thread( new ThreadStart( ThreadProc ) );
			m_thread.IsBackground = true;
			m_thread.Name = "AppThreadPool " + GetHashCode();
			m_thread.Start();
		}

		/// <summary>
		/// Get weather the thread is running or idle
		/// </summary>
		public bool IsRunning
		{
			get
			{
				return m_running;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public WaitCallback Callback
		{
			get
			{
				return m_callback;
			}

			set
			{
				m_callback = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public object StateObject
		{
			get
			{
				return m_state;
			}

			set
			{
				m_state = value;
			}
		}


		/// <summary>
		/// Execute the callback function for this thread
		/// </summary>
		public void Run()
		{
			m_goEvent.Set();
		}

		/// <summary>
		/// Stop processing and shut down the thread
		/// </summary>
		public void Stop()
		{
			m_allDone = true;
			m_goEvent.Set();
		}

		/// <summary>
		/// Blocks the calling thread until a thread terminates.
		/// </summary>
		public void Join()
		{
			m_thread.Join();
		}

		/// <summary>
		/// Raises a ThreadAbortException on the thread, to begin the process of 
		/// terminating the thread. Calling this method usually terminates the thread.
		/// </summary>
		public void Abort()
		{
			m_thread.Abort();
		}

		/// <summary>
		/// 
		/// </summary>
		private void ThreadProc()
		{
			while( !m_allDone )
			{
				m_goEvent.WaitOne();
				m_running = true;

				try
				{
					if( m_callback != null )
					{
						try
						{
							m_callback( m_state );
						}
						catch( Exception e )
						{
							if( UnhandledException != null )
							{
								UnhandledException( this, e ); 
							}

							m_log.Error( "AppThreadPool Unhandled Exception", e );
						}
					}

					m_callback = null;
					m_state = null;

					if( ThreadCompleted != null && !m_allDone )
					{
						ThreadCompleted( this );
					}
				}
				finally
				{
					m_running = false;
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public delegate void ThreadCompletedHandler( AppThread thread );

		/// <summary>
		/// 
		/// </summary>
		public delegate void UnhandledExceptionHandler( AppThread thread, Exception e );

		/// <summary>
		/// 
		/// </summary>
		public event ThreadCompletedHandler ThreadCompleted;

		/// <summary>
		/// 
		/// </summary>
		public event UnhandledExceptionHandler UnhandledException;
	}
}
